home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / tcl / tclm_1_0.lha / tclm-1.0 / MLIB / mpu_bsd386.c < prev    next >
C/C++ Source or Header  |  1993-08-16  |  10KB  |  430 lines

  1. /*-
  2.  * Copyright (c) 1993 Michael B. Durian.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 1. Redistributions of source code must retain the above copyright
  8.  *    notice, this list of conditions and the following disclaimer.
  9.  * 2. Redistributions in binary form must reproduce the above copyright
  10.  *    notice, this list of conditions and the following disclaimer in the
  11.  *    documentation and/or other materials provided with the distribution.
  12.  * 3. All advertising materials mentioning features or use of this software
  13.  *    must display the following acknowledgement:
  14.  *    This product includes software developed by Michael B. Durian.
  15.  * 4. The name of the the Author may be used to endorse or promote 
  16.  *    products derived from this software without specific prior written 
  17.  *    permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  20.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  23.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29.  * SUCH DAMAGE.
  30.  */
  31. /*
  32.  * mpu_bsd386.c,v 1.9 1993/05/07 17:45:20 durian Exp
  33.  */
  34.  
  35. #ifdef MIDIPLAY
  36. static char cvsid[] = "mpu_bsd386.c,v 1.9 1993/05/07 17:45:20 durian Exp";
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <unistd.h>
  41. #include <sys/file.h>
  42. #include <string.h>
  43. #include <errno.h>
  44. #include <sys/ioctl.h>
  45. #include <i386/isa/midiioctl.h>
  46. #include "mutil.h"
  47. #include "mdevice.h"
  48.  
  49. #define MAX_EVENT_SIZE 256
  50. /* global */
  51. volatile int StopProcessing;
  52.  
  53. static int adjust_division _ANSI_ARGS_((int division, long *div_ioctl,
  54.     int *tempo_scalar));
  55. static unsigned char double2tempo _ANSI_ARGS_((double d));
  56.  
  57. int
  58. play_tracks(dev, tracks, indices, num, repeat)
  59.     int dev;
  60.     TCHUNK *tracks;
  61.     int *indices;
  62.     int num;
  63.     int repeat;
  64. {
  65.  
  66.     return (record_tracks(dev, tracks, indices, num, NULL, repeat));
  67. }
  68.  
  69. int
  70. record_tracks(dev, p_tracks, indices, p_num, r_track, repeat)
  71.     int dev;
  72.     TCHUNK *p_tracks;
  73.     int *indices;
  74.     int p_num;
  75.     TCHUNK *r_track;
  76.     int repeat;
  77. {
  78.     TCHUNK tmptrack;
  79.     struct timeval mwait;
  80.     TCHUNK **track_list;
  81.     int *tscalars;
  82.     fd_set w_select;
  83.     fd_set r_select;
  84.     EVENT_TYPE event_type;
  85.     int endtime;
  86.     int event_len;
  87.     int i;
  88.     int select_return;
  89.     int track_done;
  90.     unsigned char event[MAX_EVENT_SIZE];
  91.  
  92.     tscalars = NULL;
  93.     track_list = NULL;
  94.     if (p_num > 0) {
  95.         /* merge play tracks */
  96.         if ((tscalars = (int *)malloc(sizeof(int) * p_num)) == NULL) {
  97.             sprintf(MidiError, "Out of memory");
  98.             return (0);
  99.         }
  100.         if ((track_list = (TCHUNK **)malloc(sizeof(TCHUNK *) * p_num))
  101.             == NULL) {
  102.             sprintf(MidiError, "Out of memory");
  103.             return (0);
  104.         }
  105.         for (i = 0; i < p_num; i++) {
  106.             tscalars[i] = 1;
  107.             track_list[i] = &p_tracks[i];
  108.             
  109.         }
  110.         init_track(&tmptrack);
  111.         endtime = merge_tracks(&tmptrack, track_list, tscalars, p_num,
  112.             0);
  113.         event_len = fix2var(endtime, event);
  114.         event[event_len] = METAEOT;
  115.         event[event_len + 1] = 0;
  116.         if (!put_smf_event(&tmptrack, event, event_len + 2)) {
  117.             sprintf(MidiError, "Couldn't add METAEOT event");
  118.             free(tscalars);
  119.             free(track_list);
  120.             free_track(&tmptrack);
  121.             return (0);
  122.         }
  123.     }
  124.  
  125.     StopProcessing = 0;
  126.     do {
  127.         track_done = 0;
  128.         rewind_track(&tmptrack);
  129.         while (!StopProcessing && !track_done) {
  130.             /* select on play */
  131.             FD_ZERO(&w_select);
  132.             if (p_num != 0)
  133.                 FD_SET(dev, &w_select);
  134.             /* also on record */
  135.             FD_ZERO(&r_select);
  136.             if (r_track != NULL)
  137.                 FD_SET(dev, &r_select);
  138.             /*
  139.              * we time out every so often to check and see
  140.              * if StopProcessing has changed
  141.              */
  142.             mwait.tv_sec = 0;
  143.             mwait.tv_usec = 100000;
  144.             if ((select_return = select(getdtablesize(), &r_select,
  145.                 &w_select, NULL, &mwait)) == -1) {
  146.                 if (errno == EINTR)
  147.                     break;
  148.                 else {
  149.                     sprintf(MidiError,
  150.                         "Error in select: %s",
  151.                         sys_errlist[errno]);
  152.                     if (tscalars != NULL)
  153.                         free(tscalars);
  154.                     if (track_list != NULL)
  155.                         free(track_list);
  156.                     free_track(&tmptrack);
  157.                     return (0);
  158.                 }
  159.             }
  160.             if (StopProcessing)
  161.                 break;
  162.             if (select_return == 0)
  163.                 continue;
  164.     
  165.             /* write event if not blocked */
  166.             if (p_num != 0 && FD_ISSET(dev, &w_select)) {
  167.                 event_len = get_smf_event(&tmptrack,
  168.                     event, &event_type);
  169.                 switch (event_len) {
  170.                 case -1:
  171.                     sprintf(MidiError,
  172.                         "Couldn't get event from tmptrack");
  173.                     if (tscalars != NULL)
  174.                         free(tscalars);
  175.                     if (track_list != NULL)
  176.                         free(track_list);
  177.                     free_track(&tmptrack);
  178.                     return (0);
  179.                 case 0:
  180.                     track_done = 1;
  181.                     break;
  182.                 default:
  183.                     if (write(dev, event, event_len) !=
  184.                         event_len) {
  185.                         sprintf(MidiError,
  186.                             "Error writing event: %s",
  187.                             sys_errlist[errno]);
  188.                         if (tscalars != NULL)
  189.                             free(tscalars);
  190.                         if (track_list != NULL)
  191.                             free(track_list);
  192.                         free_track(&tmptrack);
  193.                         return (0);
  194.                     }
  195.                     break;
  196.                 }
  197.             }
  198.  
  199.  
  200.             if (r_track != NULL && FD_ISSET(dev, &r_select)) {
  201.                 if ((event_len = read(dev, event,
  202.                     MAX_EVENT_SIZE)) == -1) {
  203.                     sprintf(MidiError,
  204.                         "Error reading event: %s",
  205.                         sys_errlist[errno]);
  206.                     if (tscalars != NULL)
  207.                         free(tscalars);
  208.                     if (track_list != NULL)
  209.                         free(track_list);
  210.                     free_track(&tmptrack);
  211.                     return (0);
  212.                 }
  213.                 if (!put_smf_event(r_track, event, event_len)) {
  214.                     sprintf(MidiError,
  215.                         "Coudln't put smf event");
  216.                     if (tscalars != NULL)
  217.                         free(tscalars);
  218.                     if (track_list != NULL)
  219.                         free(track_list);
  220.                     free_track(&tmptrack);
  221.                     return (0);
  222.                 }
  223.             }
  224.         }
  225.     } while (repeat && !StopProcessing);
  226.  
  227.     if (!StopProcessing) {
  228.         /* this waits until we're done playing */
  229.         if (ioctl(dev, MFLUSHQ, NULL) == -1)
  230.             sprintf(MidiError, "Error flushing queue: %s",
  231.                 sys_errlist[errno]);
  232.         /* check for any final data to be read */
  233.         FD_ZERO(&r_select);
  234.         if (r_track != NULL)
  235.             FD_SET(dev, &r_select);
  236.         mwait.tv_sec = 0;
  237.         mwait.tv_usec = 0;
  238.         if ((select_return = select(getdtablesize(), NULL, &w_select,
  239.             NULL, &mwait)) == -1) {
  240.             if (errno != EINTR) {
  241.                 sprintf(MidiError, "Error in select: %s",
  242.                     sys_errlist[errno]);
  243.                 if (tscalars != NULL)
  244.                     free(tscalars);
  245.                 if (track_list != NULL)
  246.                     free(track_list);
  247.                 free_track(&tmptrack);
  248.                 return (0);
  249.             }
  250.         }
  251.         if (r_track != NULL && FD_ISSET(dev, &r_select)) {
  252.             if ((event_len = read(dev, event, MAX_EVENT_SIZE))
  253.                 == -1) {
  254.                 sprintf(MidiError, "Error reading event: %s",
  255.                     sys_errlist[errno]);
  256.                 if (tscalars != NULL)
  257.                     free(tscalars);
  258.                 if (track_list != NULL)
  259.                     free(track_list);
  260.                 free_track(&tmptrack);
  261.                 return (0);
  262.             }
  263.             if (!put_smf_event(r_track, event, event_len)) {
  264.                 sprintf(MidiError, "Coudln't put smf event");
  265.                 if (tscalars != NULL)
  266.                     free(tscalars);
  267.                 if (track_list != NULL)
  268.                     free(track_list);
  269.                 free_track(&tmptrack);
  270.                 return (0);
  271.             }
  272.         }
  273.     }
  274.     if (tscalars != NULL)
  275.         free(tscalars);
  276.     if (track_list != NULL)
  277.         free(track_list);
  278.     free_track(&tmptrack);
  279.     return (1);
  280. }
  281.  
  282. int
  283. stop_processing(dev)
  284.     int dev;
  285. {
  286.  
  287.     StopProcessing = 1;
  288.     /* if we leave, leave now - don't hang on close */
  289.     if (ioctl(dev, MCLRQ, NULL) == -1) {
  290.         sprintf(MidiError, "Error clearing queue: %s",
  291.             sys_errlist[errno]);
  292.         return (0);
  293.     }
  294.     return (0);
  295. }
  296.  
  297. int
  298. open_midi_device(mode)
  299.     PlayMode mode;
  300. {
  301.     mode_t m;
  302.     int dev;
  303.  
  304.     switch (mode) {
  305.     case PLAY:
  306.         m =  O_WRONLY;
  307.         break;
  308.     case RECORD:
  309.         m = O_RDONLY;
  310.         break;
  311.     case PLAYRECORD:
  312.         m = O_RDWR;
  313.         break;
  314.     }
  315.     if ((dev = open("/dev/midi0", m)) == -1) {
  316.         sprintf(MidiError, "Couldn't open /dev/midi0: %s",
  317.             sys_errlist[errno]);
  318.     }
  319.     return (dev);
  320. }
  321.  
  322. int
  323. init_midi_device(dev, hd, reltempo)
  324.     int dev;
  325.     HCHUNK *hd;
  326.     double reltempo;
  327. {
  328.     long div_ioctl;
  329.     int tscalar;
  330.     unsigned char fixreltempo;
  331.  
  332.     if (!adjust_division(hd->division, &div_ioctl, &tscalar)) {
  333.         sprintf(MidiError, "Bad division value.  Must be on of \
  334. 48, 72, 96, 120, 144, 168, 192 or an integer multiple thereof");
  335.         return (0);
  336.     }
  337.  
  338.     if (ioctl(dev, div_ioctl, NULL) == -1) {
  339.         sprintf(MidiError, "Couldn't set division: %s",
  340.             sys_errlist[errno]);
  341.         return (0);
  342.     }
  343.     if (ioctl(dev, MTSCALAR, &tscalar) == -1) {
  344.         sprintf(MidiError, "Couldn't set tscalar: %s",
  345.             sys_errlist[errno]);
  346.         return (0);
  347.     }
  348.     fixreltempo = double2tempo(reltempo);
  349.     if (ioctl(dev, MSETRELTMP, &fixreltempo) == -1) {
  350.         sprintf(MidiError, "Couldn't set relative tempo: %s",
  351.             sys_errlist[errno]);
  352.         return (0);
  353.     }
  354.  
  355.     return (1);
  356. }
  357.  
  358. int
  359. start_midi_device(dev, mode)
  360.     int dev;
  361.     PlayMode mode;
  362. {
  363.  
  364.     /* automatically started by open */
  365.     return (1);
  366. }
  367.  
  368. int
  369. stop_midi_device(dev, mode)
  370.     int dev;
  371.     PlayMode mode;
  372. {
  373.     /* automatically stopped by close */
  374.     return (1);
  375. }
  376.  
  377. int
  378. close_midi_device(dev)
  379.     int dev;
  380. {
  381.  
  382.     close(dev);
  383.     return (1);
  384. }
  385.  
  386. int
  387. adjust_division(division, div_ioctl, tempo_scalar)
  388.     int division;
  389.     long *div_ioctl;
  390.     int *tempo_scalar;
  391. {
  392.     long ioctls[] = {MRES192, MRES168, MRES144, MRES120, MRES96,
  393.         MRES72, MRES48};
  394.     int divs[] = {192, 168, 144, 120, 96, 72, 48};
  395.     int i;
  396.     int ret_val;
  397.  
  398.     ret_val = 0;
  399.     for (i = 0; i < sizeof(divs) / sizeof(divs[0]); i++) {
  400.         if (division % divs[i] == 0) {
  401.             *div_ioctl = ioctls[i];
  402.             *tempo_scalar = 1000 * division / divs[i];
  403.             ret_val = 1;
  404.             break;
  405.         }
  406.     }
  407.     return (ret_val);
  408. }
  409.  
  410. unsigned char
  411. double2tempo(d)
  412.     double d;
  413. {
  414.     double bit_vals[] = {2.0, 1.0, 0.5, 0.25, 0.125, 0.0625,
  415.         0.03125, 0.015625};
  416.     int i;
  417.     unsigned char tempo_scalar;
  418.  
  419.     for (i = 0; i < 8; i++) {
  420.         if (d < bit_vals[i])
  421.             tempo_scalar = (tempo_scalar << 1) & ~1;
  422.         else {
  423.             tempo_scalar = (tempo_scalar << 1) | 1;
  424.             d -= bit_vals[i];
  425.         }
  426.     }
  427.     return(tempo_scalar);
  428. }
  429. #endif
  430.